package com.xqboss.apps.service.order;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xqboss.apps.constant.LockKey;
import com.xqboss.apps.domain.order.OrderMain;
import com.xqboss.apps.domain.order.OrderRefund;
import com.xqboss.apps.dto.order.ApplyRefundDto;
import com.xqboss.apps.dto.order.GetRefundListDto;
import com.xqboss.apps.dto.order.HandlerRefundDto;
import com.xqboss.apps.enums.order.RefundStatusEnum;
import com.xqboss.apps.mapper.order.OrderRefundMapper;
import com.xqboss.common.core.domain.model.LoginUser;
import com.xqboss.common.core.redis.lock.LockObject;
import com.xqboss.common.core.redis.lock.RedisLock;
import com.xqboss.common.exception.ServiceException;
import com.xqboss.common.utils.SecurityUtils;
import com.xqboss.common.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;

/**
 * @author Trent
 * @date 2023/9/7
 */
@Service
public class OrderRefundService extends ServiceImpl<OrderRefundMapper, OrderRefund> {

    @Autowired
    private OrderService orderService;

    /**
     * 申请退款
     *
     * @param dto
     */
    public void applyRefund(ApplyRefundDto dto) {
        OrderMain orderMain = orderService.getById(dto.getOrderId());
        if(Objects.isNull(orderMain)){
            throw new ServiceException("订单不存在！");
        }
        // 对退单金额进行检测
        if(dto.getApplyAmount().compareTo(orderMain.getActualPaymentAmount()) > 0){
            throw new ServiceException("申请退款金额不能超过订单实际支付金额！");
        }
        orderService.applyRefund(dto.getOrderId());
        OrderRefund orderRefund = new OrderRefund();
        orderRefund.setId(IdUtil.getSnowflakeNextId());
        orderRefund.setOrderMainId(dto.getOrderId());
        orderRefund.setApplyAmount(dto.getApplyAmount());
        orderRefund.setPayType(dto.getPayType());
        orderRefund.setPayAccount(dto.getPayAccount());
        orderRefund.setApplyReason(dto.getApplyReason());
        orderRefund.setRefundStatus(RefundStatusEnum.AUDIT);
        LoginUser loginUser = SecurityUtils.getLoginUser();
        orderRefund.setApplyUserId(loginUser.getUserId());
        orderRefund.setApplyUserName(loginUser.getNickName());
        save(orderRefund);
        // 更新订单退款状态
        orderService.updateRefundStatus(dto.getOrderId(), orderRefund.getRefundStatus());
    }


    /**
     * 撤销退款
     */
    @RedisLock(lockKey = LockKey.LOCK_ORDER_REFUND)
    public void revokeRefund(@LockObject Long refundId) {
        OrderRefund refund = getById(refundId);
        if (Objects.isNull(refund)) {
            throw new ServiceException("退单不存在！");
        }
        if (refund.getRefundStatus() == RefundStatusEnum.CANCEL){
            throw new ServiceException("申请已撤销！");
        }
        if (refund.getRefundStatus() != RefundStatusEnum.AUDIT) {
            throw new ServiceException("无法撤销已处理退单！");
        }
        boolean update = update(new LambdaUpdateWrapper<OrderRefund>()
                .set(OrderRefund::getRefundStatus, RefundStatusEnum.CANCEL)
                .eq(OrderRefund::getId, refund.getId()));
        if (!update) {
            throw new ServiceException("操作失败！");
        }
        orderService.updateRefundStatus(refund.getOrderMainId(), RefundStatusEnum.CANCEL);
    }



    /**
     * 处理退单
     */
    @RedisLock(lockKey = LockKey.LOCK_ORDER_REFUND)
    public void handlerRefund(@LockObject(valueFields = "id") HandlerRefundDto dto) {
        OrderRefund refund = getById(dto.getId());
        if (Objects.isNull(refund)) {
            throw new ServiceException("退单不存在！");
        }
        if (refund.getRefundStatus() == RefundStatusEnum.CANCEL){
            throw new ServiceException("无法处理已撤销退单！");
        }
        if (refund.getRefundStatus() != RefundStatusEnum.AUDIT) {
            throw new ServiceException("重复处理退单！");
        }
        // 对退单金额进行检测
        if(dto.getStatus() == RefundStatusEnum.REFUND){
            if(dto.getRefundAmount().compareTo(refund.getApplyAmount()) > 0){
                throw new ServiceException("实际退款金额不能大于申请金额");
            }
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        boolean update = update(new LambdaUpdateWrapper<OrderRefund>()
                .set(OrderRefund::getRefundStatus, dto.getStatus())
                .set(OrderRefund::getRefundAmount, dto.getRefundAmount())
                .set(OrderRefund::getHandlerRemarks, dto.getHandlerRemarks())
                .set(OrderRefund::getHandlerUserId, loginUser.getUserId())
                .set(OrderRefund::getHandlerUserName, loginUser.getNickName())
                .set(OrderRefund::getHandlerTime, LocalDateTime.now())
                .eq(OrderRefund::getId, refund.getId()));
        if (!update) {
            throw new ServiceException("操作失败！");
        }
        orderService.updateRefundStatus(refund.getOrderMainId(), dto.getStatus());
    }

    /**
     * 获取退单列表
     *
     * @return
     */
    public List<OrderRefund> getRefundList(GetRefundListDto dto) {
        LambdaQueryWrapper<OrderRefund> queryWrapper = new LambdaQueryWrapper<>();
        if (dto.getOrderId() != null) {
            queryWrapper.eq(OrderRefund::getOrderMainId, dto.getOrderId());
        }
        if(dto.getRefundStatus() != null){
            queryWrapper.eq(OrderRefund::getRefundStatus, dto.getRefundStatus());
        }
        if (StringUtils.isNotEmpty(dto.getSearch())) {
            queryWrapper.or(true, wrapper -> {
                wrapper.eq(OrderRefund::getOrderMainId, dto.getSearch())
                        .or()
                        .eq(OrderRefund::getApplyUserName, dto.getSearch())
                        .or()
                        .eq(OrderRefund::getId, dto.getSearch());
            });
        }
        return list(queryWrapper);
    }


    /**
     * 获取退单详情
     *
     * @return
     */
    public OrderRefund getRefund(Long id) {
        OrderRefund refund = getById(id);
        if (refund == null) {
            throw new ServiceException("退单不存在！");
        }
        return refund;
    }
}
